package com.server.net.message;

import com.server.net.session.Session;
import com.server.net.session.SessionManager;
import io.netty.channel.Channel;

import java.util.LinkedList;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 如何解决 Netty Channel.isWritable 返回 false
 * https://blog.csdn.net/vivisran/article/details/115107225
 * 缓存msg，channelWritabilityChanged触发时再尝试发送
 * WRITE_BUFFER_WATER_MARK 设置大一点，也可尽量减少这种情况出现，但治标不治本
 */
public class MsgNotWritableCacheManager {

    private static final MsgNotWritableCacheManager instance = new MsgNotWritableCacheManager();

    public static MsgNotWritableCacheManager getInstance() {
        return instance;
    }

    /**
     * key = getChannel().id().asLongText()
     */
    private ConcurrentHashMap<String, LinkedList<MsgPack>> cache = new ConcurrentHashMap<>();

    public void pushNotWritableMsg(MsgPack msgPack) {
        String channelId = msgPack.getChannel().id().asLongText();
        LinkedList<MsgPack> list = cache.get(channelId);
        if (null == list) {
            list = new LinkedList<>();
            cache.put(channelId, list);
        }
        list.add(msgPack);

    }

    public void trySendMsgAgain(Channel channel) {
        if (!channel.isActive()) {
            return;
        }
        if (!channel.isWritable()) {
            return;
        }
        String channelId = channel.id().asLongText();
        Session Session = SessionManager.getInstance().getSessionByChannelId(channelId);
        if (null == Session) {
            return;
        }
        LinkedList<MsgPack> list = cache.get(channelId);
        if (null == list) {
            return;
        }
        while (!list.isEmpty()) {
            MsgPack msgPack = list.peek();//检索但不删除此列表的头部（第一个元素）
            boolean result = Session.sendMsg(msgPack.getMainProtocl().toBuilder());
            if (!result) {
                break;
            }
            //发送成功再删除缓存消息
            list.pop();//删除并返回第一个元素
        }
    }

    /**
     * 登录、下线、异常 时清除消息缓存
     */
    public void clear(Channel channel) {
        String channelId = channel.id().asLongText();
        cache.remove(channelId);
    }
}
